#include <cstdio>


#define MAX_BLOCKS 90


/***********************************************/


template <class C>
inline void swap (C &a, C &b)
{
	C c;
	c = a;
	a = b;
	b = c;
}

template <class C>
inline void sort(C &x, C &y, C &z) {
	if (x > y)
		swap(x, y);
	if (x > z)
		swap(x, z);
	if (y > z)
		swap(y, z);
}


/***********************************************/


struct Block
{
	int x, y, h, max;

	inline void set (int x, int y, int h) {
		this->x = x;
		this->y = y;
		this->h = h;
		this->max = h;
	}
};


struct BlockParents
{
	Block *first[MAX_BLOCKS], **last;

	inline void reset () {last = first; *last = 0;}

	inline void pop (Block *b) {*last = b; ++last; *last = 0;}

	inline Block *& operator [] (size_t n) {return first[n];}
};


struct BlockGraph
{
	Block b[MAX_BLOCKS], *last;
	BlockParents parents[MAX_BLOCKS];
	int max, size;

	inline void reset () {last = b; max = 0; size = 0;}

	inline void readline ();

	inline void calculate ();

	void update (int n);

	inline void check_max (Block *pb) {
		if (this->max < pb->max)
			this->max = pb->max;
	}

	inline void insert (int x, int y, int h) {
		last->set(x, y, h);
		check_max (last);
		parents[size].reset();
		calculate();
		++size;
		++last;
	}
};


/***********************************************/


inline int compare (const Block *b1, const Block *b2)
{
	if (b1->x > b2->x && b1->y > b2->y)
		return 1;
	if (b1->x < b2->x && b1->y < b2->y)
		return -1;
	return 0;
}


void BlockGraph::readline ()
{
	int x, y, z;

	scanf("%d %d %d", &x, &y, &z);
	sort(x, y, z);
	insert(x, y, z);
	if (y < z) {
		swap(y, z);
		insert(x, y, z);
	}
	if (x < z) {
		swap(x, z);
		insert(x, y, z);
	}
}


void BlockGraph::calculate ()
{
	int &last_block = this->size, i, tentative_max;
	Block *bi;

	for (i = 0, bi = b; i < last_block; ++i, ++bi)
	{
		int cmp = compare (bi, last);
		switch (cmp)
		{
			case -1: // El bloque i puede estar encima del último bloque.
			{
				parents[i].pop(last);
				tentative_max = bi->max + last->h;
				if (last->max < tentative_max) {
					last->max = tentative_max;
					check_max (last);
				}
				break;
			}

			// case 0: // Ningún bloque puede estar encima del otro.

			case 1: // El último bloque puede estar encima del bloque i.
			{
				parents[last_block].pop(bi);
				break;
			}
		}
	}

	update (last_block);
}


void BlockGraph::update (int n)
{
	int tentative_max, i;
	Block *bn, **pb;

	bn = b + n;
	for (pb = parents[n].first; *pb; ++pb)
	{
		tentative_max = bn->max + (*pb)->h;
		if ((*pb)->max < tentative_max) {
			(*pb)->max = tentative_max;
			check_max (*pb);
			update (*pb - b);
		}
	}
}


/***********************************************/


BlockGraph bg;


int main ()
{
	int
		test_case = 1,
		total_blocks;

	scanf("%d", &total_blocks);
	while (total_blocks)
	{
		bg.reset();
		for (int i = 0; i < total_blocks; ++i)
		{
			bg.readline();
		}

		printf("Case %d: maximum height = %d\n", test_case, bg.max);
		++test_case;

		scanf("%d", &total_blocks);
	}

	return 0;
}